package cn.le.io;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.Future;

/**
 * Java NIO中有三种异步通道：AsynchronousFileChannel、AsynchronousServerSocketChannel、AsynchronousSocketChannel。
 *
 * 异步调用主要有2中方式:将来式,回调式
 *
 */
public class AsynchronousChannelDemo {

    Path file = Paths.get("C:/Users/admin/Documents/SQL/我的项目.sql");

    public static void main(String[] args) throws IOException {

        AsynchronousChannelDemo demo = new AsynchronousChannelDemo();
        long a = System.currentTimeMillis();
        demo.futureTense();
        long b = System.currentTimeMillis();
        demo.callback();
        long c = System.currentTimeMillis();

        System.out.println((b-a));
        System.out.println((c-b));
    }

    /**
     * 将来式: 用Future接口来保存异步操作的处理结果,这意味着当前线程不会因为较慢的io操作而停止,
     * 而且开启一个单独的线程发起io操作,并且在操作完成时返回结果,于此同时,主线程可以继续执行其它需要完成的任务
     */
    public void futureTense() throws IOException {

        /*
        AsynchronousFileChannel会关联线程池,可以在创建时指定,如果没有指定,jvm会为其分配一个系统
        默认的线程池(可能会与其他通道共享),默认线程池是由AsynchronousChannelGroup类定义属性进行配置的.
         */

        AsynchronousFileChannel channel = AsynchronousFileChannel.open(file);
        ByteBuffer buffer = ByteBuffer.allocate(100);

        Future<Integer> result = channel.read(buffer,0);
        //如果任务完成返回true,Future可以得到线程执行的返回值,不过主线程在获取返回值时是阻塞的
        while (!result.isDone())
        {
            System.out.println("do sometingelse");
        }
        buffer.flip();
        System.out.println(Charset.forName("utf-8").decode(buffer));
    }

    /**
     *回调时的基本思想是主线程会派一个CompletionHandler到独立的线程中执行io操作,
     * 当io操作完成后,会调用CompletionHandler的completed的failed()方法.
     *异步事件一成功或失败就需要马上采取行动时,一般会采用回调式.
     * 在异步io活动结束后,接口CompletionHandler<v,a>会被调用,其中v是结果类型,A是提供结果
     * 的附着对象
     *
     */
    public void callback() throws IOException {

        AsynchronousFileChannel channel = AsynchronousFileChannel.open(file);
        ByteBuffer buffer = ByteBuffer.allocate(100);
        channel.read(buffer, 0, buffer, new CompletionHandler<Integer, ByteBuffer>() {
            //操作完成时调用
            @Override
            public void completed(Integer result, ByteBuffer attachment) {
                attachment.flip();
                System.out.println(Charset.forName("utf-8").decode(attachment));
            }
            //当操作失败时调用。
            @Override
            public void failed(Throwable exc, ByteBuffer attachment) {
                System.out.println("parsefile failed");
                exc.printStackTrace();
            }
        });


    }
}












